const { Filter } = require("../../display/filters")
const { Display, translateBloon } = require("../../display/general")
const { ignoreFunction } = require("../../util/ignore")
const { getModelType } = require("../../util/utils")
const { parseEmission } = require("../emission/emission")
const { parseFilters } = require("../filter/parse")
const { parseProjectileBehavior } = require("../projectile/behavior")

const models = {}

//----------------------------------------------------
// attack behaviors
//----------------------------------------------------

models.TargetMoabModel = (b, a) => {
    a.filters.push(new Filter('filterInMoabs', 'can only target blimps'))
}

models.TargetGrapplableModel = (b, a) => {
    a.filters.push(
        b.hooks < b.zomgHooksRequired ? new Filter(`filterOutTags`, `can not affect ZOMG`, 'ZOMG') : null,
        b.hooks < b.badHooksRequired ? new Filter(`filterOutTags`, `can not affect BAD`, 'BAD') : null,
    )
}

models.RotateToPointerModel = (b, a) => {
    if (b.rate >= 9999999) return
    a.meta.turnRate = Display.unitAny(b.rate, '°/s').out
}

models.TargetInFrontOfAirUnitModel = ignoreFunction

models.UsePresetTargetModel = ignoreFunction

models.PathMovementFromScreenCenterPatternModel = ignoreFunction

models.GyrfalconPatternModel = (b, a) => {
    const { parseProjectile } = require("../projectile/parse")
    const finalProj = parseProjectile(b.grabProjectileModel)
    finalProj.meta.initialDamage = {}
    finalProj.meta.grappleDamage = {}

    let fakeProj = { damage: null, damageType: null, damageMods: [], notes: [] }
    parseProjectileBehavior(b.initialDamageModel, fakeProj)
    parseProjectileBehavior(b.regrowDamageModifierModel, fakeProj)
    if (b.initialDamageMoabModifierModel) {
        parseProjectileBehavior(b.initialDamageMoabModifierModel, fakeProj)
    }
    finalProj.meta.initialDamage = fakeProj

    fakeProj = { damage: null, damageType: null, damageMods: [], notes: [] }
    parseProjectileBehavior(b.grapplingDamageModel, fakeProj)
    parseProjectileBehavior(b.regrowDamageModifierModel, fakeProj)
    if (b.initialDamageMoabModifierModel) {
        parseProjectileBehavior(b.grapplingDamageMoabModifierModel, fakeProj)
    }
    finalProj.meta.grappleDamage = fakeProj

    const arr = ['lead', 'ceramic', 'moab', 'bfb', 'zomg', 'ddt']
    arr.forEach(e => {
        if (b[e + 'PiercePenalty']) {
            finalProj.piercePenalty.push({
                keyword: translateBloon(e),
                value: Display.additive(b[e + 'PiercePenalty'])
            })
        }
    })

    a.projectile = finalProj
    a.meta.grappleCooldown = Display.time(b.grappleDamageRate)
    a.meta.postGrabCooldown = Display.time(b.cooldown)
    a.meta.speed = b.maxSpeed
}

models.AttackFilterModel = (b, a) => {
    a.filters.push(...parseFilters(b.filters))
}

//----------------------------------------------------
// weapon behaviors
//----------------------------------------------------

models.AlternateProjectileModel = (b, w) => {
    const { parseProjectile } = require("../projectile/parse")
    const proj = parseProjectile(b.projectile)
    parseEmission(b.emissionModel, proj, null)
    proj.perAttacks = b.interval // this is not time
    w.projectile.push(proj)
}

models.BloonDistanceRateBonusModel = (b, w) => {
    w.meta.attackSpeedBonusPerUnit = Display.additivePercent(b.rateBonusPerRange)
    w.meta.attackSpeedBonusPerUnitMaxStacks = Display.additivePercent(b.rangeMax * b.rateBonusPerRange)
}

models.BloonsInRangeAttackSpeedModel = (b, w) => {
    w.meta.attackSpeedBonusPerBloonStack = Display.additivePercent(b.rateIncreasePerStack)
    w.meta.attackSpeedBonusPerBloons = b.bloonsPerStack
    w.meta.attackSpeedBonusPerBloonStackMax = Display.additivePercent(b.maxStacks * b.rateIncreasePerStack)
}

models.BonusProjectileAfterIntervalModel = (b, w) => {
    const { parseProjectile } = require("../projectile/parse")
    const proj = parseProjectile(b.projectileModel)
    proj.meta.perAttacks = b.interval // this is not time
    proj.meta.cooldown = Display.time(b.cooldown)
    w.projectile.push(proj)
}

models.BurstWeaponBehaviorModel = (b, w) => {
    w.meta.burstInterval = Display.time(b.interval)
    w.meta.burstCount = b.count
}

models.ChangeProjectilePerEmitModel = (b, w) => {
    const { parseProjectile } = require("../projectile/parse")
    const proj = parseProjectile(b.changedProjectileModel)
    w.projectile.push({
        projectile: proj,
        perAttacks: b.forProjectileCount // this is not time
    })
}

models.CreateSequencedTypedTowerCurrentIndexModel = (b, w) => {
    const { parseTower } = require("../tower/parse")
    w.projectile[0].meta.subTowers = b.towers.map(parseTower)
}

models.CheckAirUnitOverTrackModel = ignoreFunction

models.CritMultiplierModel = (b, w) => {
    w.meta.critDamage = b.damage
    if (b.lower === b.upper) {
        w.meta.critHits = b.lower
    } else {
        w.meta.minCritHits = b.lower
        w.meta.maxCritHits = b.upper
    }
}

models.CritRollWithDistanceModel = (b, w) => {
    w.meta.critDamageMultiplier = Display.multiplier(b.damageMultiplier)
    w.meta.critChance = Display.percent(b.chance)
    w.meta.critChanceBonusPerUnitFromTarget = Display.additivePercent(b.bonusPerDistance)
}

// might parse this later, now just describe it manually
models.DuplicateProjectilePerEmitModel = ignoreFunction

models.EmissionsPerRoundFilterModel = (b, w) => {
    w.meta.maxEmissionPerRound = b.count
}

// for buccaneer attacks
models.FireWhenAlternateWeaponIsReadyModel = (b, w) => {
    w.meta.isAlternate = true
}

models.JungleVineLimitProjectileModel = ignoreFunction

models.LifeBasedAttackSpeedModel = (b, w) => {
    w.meta.attackSpeedBonusPerLifeLost = Display.additivePercent(b.ratePerLife)
    w.meta.attackSpeedBonusPerLifeLostMaxStacks = Display.additivePercent(b.ratePerLife * b.lifeCap)
    w.meta.attackSpeedBonusPerLifeLostBase = Display.additivePercent(b.baseRateIncrease)
}

models.LimitProjectileModel = (b, w) => {
    //w.meta.projectileLimit = b.limit
    w.meta.newProjectileDelay = Display.time((b.delayInFrames + 1) / 60)
}

models.LeakDangerAttackSpeedModel = (b, w) => ignoreFunction

models.MagusPerfectusGraveyardModel = ignoreFunction

models.PauseOtherAttacksModel = (b, w) => {
    w.meta.pauseOtherAttackLifespan = Display.time(b.lifespan)
}

models.PierceFromLivesGainedModel = (b, w) => {
    w.meta.piercePercentPerLife = Display.additivePercent(b.piercePercentPerLife)
    w.meta.piercePercentPerLifeMaxStacks = b.lifeCap
}

models.RandomAngleOffsetModel = (b, w) => {
    w.meta.randomAngleRange = `${Display.angle(b.minOffset)}~${Display.angle(b.maxOffset)}`
}

models.RandomRateModel = (b, w) => {
    w.attackCooldown = `${w.attackCooldown}(+0~${Display.time(b.offsetRate)})`
}

models.RateBasedAnimationOffsetModel = ignoreFunction

models.SpinModel = (b, w) => {
    w.meta.spinSpeed = Display.unitAny(b.rotationPerSecond, '°/s')
}

models.StandoffModel = (b, w) => {
    w.meta.attackSpeedBonusWith1BloonInrange = Display.additivePercent(b.maxRateIncrease)
    w.meta.attackSpeedDecreasePerAdditionalBloonInrange = Display.additivePercent(-b.rateDecreasePerBloon)
}

models.SubTowerFilterModel = (b, w) => {
    w.meta.maxSubTowers = b.maxNumberOfSubTowers
}

models.SwapProjectileModel = (b, w) => {
    const { parseProjectile } = require("../projectile/parse")
    w.projectile.push(parseProjectile(b.projectileModelB))
}

models.TheBlazingSunModel = (b, w) => {
    const { parseProjectile } = require("../projectile/parse")
    w.projectile.push(parseProjectile(b.burnBehaviorArea))
}

models.VagrantWeaponBehaviorModel = (b, w) => {
    w.meta.attackSpeedBonusWithNoTowerInRange = Display.additivePercent(b.noTowersRateBonus)
    w.meta.attackSpeedDecreasePerAditionalTowerInRange = Display.additivePercent(-b.towerRangeBonusReduction)
    if (b.bloonInRangeAttackSpeedBuff) {
        w.meta.attackSpeedBonusPerBloonInRange = Display.additivePercent(b.bloonInRangeAttackSpeedBuff)
        w.meta.attackSpeedBonusPerBloonInRangeMax = Display.additivePercent(b.maxBloonAttackSpeedBuff)
    }
}

models.WeaponRateMinModel = (b, w) => {
    w.minAttackCooldown = Display.time(b.min)
    w.attackCooldown = Display.time(Math.max(b.min, w.attackCooldown.og))
}

function parseAttackBehavior(b, w, type = null) {
    if (!type) type = getModelType(b)
    if (models[type]) models[type](b, w)
    else w.behaviors.push(b)
}

module.exports = {
    parseAttackBehavior,
}